package RE.impl.ex3;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import RE.api.*;
import RE.rep.*;
import RE.rep.Relation.RelationName;
import RE.rep.TokenWithNER.NamedEntityType;

/**
 * @author zirolny 30795560 charika 30534360
 */
public class Ex3FullConfiguration implements Configuration<SentenceWithDependenciesAndNER> {
	private LinkedList<Rule<SentenceWithDependenciesAndNER>> configuration;
	
	@Override
	public List<Rule<SentenceWithDependenciesAndNER>> getConfiguration() {
		return configuration;
	}
	
	@Override
	public void generateConfiguration() {
		configuration = new LinkedList<Rule<SentenceWithDependenciesAndNER>>();	
		
		configuration.add(new KillRuleActive());
		configuration.add(new KillRuleSomeonesAssassin());
		configuration.add(new KillRuleGuilty());
		configuration.add(new KillRuleAssassinationOf());
		configuration.add(new KillRulePassiveFixed());
		configuration.add(new KillRuleAllPeople());
		
		configuration.add(new LocatedInRuleComma());
		configuration.add(new LocatedInRuleLocInLocTokens());
		configuration.add(new LocatedInRuleLocInLocDeps());
		configuration.add(new LocatedInRuleLocationsLocation());
		
		configuration.add(new OrgBasedRuleIn());
		configuration.add(new OrgBasedRuleOf());
		configuration.add(new OrgBasedRuleCapitalizedNNP());
		configuration.add(new OrgBasedRuleBasedIn());
		configuration.add(new OrgBasedRuleHeadquartesIn());
		configuration.add(new OrgBasedRuleLocationAfterOrganization());
		configuration.add(new OrgBasedRuleLocationAroundOraganization());
		
		configuration.add(new WorkForRuleBrackets());
		configuration.add(new WorkForRuleOfThe());
		configuration.add(new WorkForRuleOfFixed());
		configuration.add(new WorkForRuleWhoWorksFixed());
		configuration.add(new WorkForRuleProfessionFixed()); 
		configuration.add(new WorkForRulePersonForOrg());
		configuration.add(new WorkForRulePersonOfOrg());
		configuration.add(new WorkForRulePersonAppos());
		configuration.add(new WorkForRuleOrganizationsPerson());
		configuration.add(new WorkForRuleOrganizationsEmployee());
		configuration.add(new WorkForRulePersonOfTheOrg());
		configuration.add(new WorkForRulePersonsOrganization());
		
		configuration.add(new LiveInRuleSomeonesHome());
		configuration.add(new LiveInRuleProfession());
		configuration.add(new LiveInCommaAndAge());
		configuration.add(new LiveInRuleHomeInFixed());
		configuration.add(new LiveInPlaceProfessionsFixed());
		configuration.add(new LiveInRuleLocationAfterPerson());
		configuration.add(new LiveInRuleDepPersonLoc());
		configuration.add(new LiveInRulePresidentsLocation());
		configuration.add(new LiveInRuleLocationsPerson());
		configuration.add(new LiveInRulePersonAppos());
		configuration.add(new LiveInRulePersonOfLoc());
		configuration.add(new LiveInRulePersonFromLoc());
		configuration.add(new LiveInRuleLeadersLocation());
	}

	public static class KillRuleActive implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.KillRuleActive();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class KillRuleSomeonesAssassin implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.KillRuleSomeonesAssassin();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class KillRuleGuilty implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.KillRuleGuilty();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class KillRuleAssassinationOf implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.KillRuleAssassinationOf();
			return oldRule.applyRule(sentence);
		}
	}
	
	// This rule looks for patterns in passive form like "Y was killed by X" or one of kill synonyms
	public static class KillRulePassiveFixed implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			//preparing list of killing synonyms
			List<String> killSynonyms=new ArrayList<String>();
			killSynonyms.add("kill");
			killSynonyms.add("murder");
			killSynonyms.add("assassinate");
			killSynonyms.add("bomb");
			killSynonyms.add("shoot");
			killSynonyms.add("dispatch");
			killSynonyms.add("crucify");
			killSynonyms.add("fire");
			killSynonyms.add("drown");
			killSynonyms.add("suffocate");
			killSynonyms.add("strangle");
			killSynonyms.add("poison");
			killSynonyms.add("slay");
			killSynonyms.add("slaughter");
			killSynonyms.add("exterminate");
			killSynonyms.add("gun");
			
			//preparing list of location prepositions
			List<String> locationPrepositions=new ArrayList<String>();
			locationPrepositions.add("in");
			locationPrepositions.add("against");
			locationPrepositions.add("the");
			locationPrepositions.add("a");
			locationPrepositions.add("an");
				
			List<? extends Token> tokens=sentence.getTokens();			
			String sentenceID=tokens.get(0).getSentenceId();
			//looking for the passive pattern
			for(int i=1;i<tokens.size()-1;i++){
				if(killSynonyms.contains(tokens.get(i).getLemma()) && tokens.get(i-1).getLemma().intern() == "be"){
					
					String arg1="";
					int j = i - 1;
					
					
					boolean isNPbefore=false;
					
					//looking for NNP phrase before the kill verb
					while(true){
						
						while((j >= 0) && (tokens.get(j).getPos() != POS.NNP))
							j--;
						
						//no NNP was found
						if (j == -1){
							isNPbefore=false;
							break;
						}
						
						//preparing the second argument (the NNP before "be killed by")
						arg1 = tokens.get(j).getWord();
						j--;
						while ((j >= 0) && (tokens.get(j).getPos() == POS.NNP)) {
							
							arg1=tokens.get(j).getWord()+" "+arg1;
							j--;
						}
						
					
						//checking if the argument we found isn't a location
						if(j>=0 &&  (locationPrepositions.contains((tokens.get(j).getWord())) || tokens.get(j).getWord().intern() == "at" )){
							arg1="";
							continue;
						}
						else
						{
							isNPbefore=true;
							break;
						}
					}
					
					if(!isNPbefore)
						continue;
					
					j=i+1;
					
					//looking for the word "by"
					while ((j < tokens.size()) && ((tokens.get(j).getWord().intern() != "by"))) {
						j++;
					}
					//no "by" was found
					if (j == tokens.size())
						continue;
					
					String arg2 = "";
					j++;
					
					//skipping the words which aren't NNP
					while ((j < tokens.size()) && (tokens.get(j).getPos() != POS.NNP))
						j++;
					
					//preparing the first argument (the NNP after "killed by")
					if (j < tokens.size()) {
						arg2 = tokens.get(j).getWord();
						j++;
					}
					while ((j < tokens.size()) && (tokens.get(j).getPos() == POS.NNP)) {
						arg2=arg2 + " " + tokens.get(j).getWord();
						j++;
					}
					
					
					//if none of the arguments is empty, adding it
					if(arg1.intern()!="" && arg2.intern()!="")
						set.add(new Relation(Relation.RelationName.Kill,arg2,arg1,sentenceID));
				}
			}
			
			return set;
		}
	}
	
	// In the sentences related to killing, each person killed all the other people
	public static class KillRuleAllPeople implements Rule<SentenceWithDependenciesAndNER> {
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			ArrayList<Relation> relations = new ArrayList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			
			//preparing a list of various synonyms for the word kill
			List<String> killSynonyms = new ArrayList<String>();
			killSynonyms.add("kill");
			killSynonyms.add("murder");
			killSynonyms.add("assassinate");
			killSynonyms.add("bomb");
			killSynonyms.add("shoot");
			killSynonyms.add("dispatch");
			killSynonyms.add("crucify");
			killSynonyms.add("fire");
			killSynonyms.add("drown");
			killSynonyms.add("suffocate");
			killSynonyms.add("strangle");
			killSynonyms.add("poison");
			killSynonyms.add("slay");
			killSynonyms.add("slaughter");
			killSynonyms.add("exterminate");
			killSynonyms.add("gun");
			killSynonyms.add("wound");
			
			// Check if the sentence is related to killing
			boolean kill = false;
			for (int i = 0; i < tokens.size(); i++) {
				if (killSynonyms.contains(tokens.get(i).getLemma())) {
					kill = true;
					break;
				}
			}
			if (!kill)
				return relations;
			
			// Get all the people in the sentence
			ArrayList<String> people = new ArrayList<String>();
			for (int i = 0; i < tokens.size(); i++) {
				if ((tokens.get(i).getNamedEntityType() == NamedEntityType.PERSON) && ((i == tokens.size() - 1) || (tokens.get(i + 1).getNamedEntityType() != NamedEntityType.PERSON))) {
					StringBuilder person = new StringBuilder(tokens.get(i).getWord());
					int j = i - 1;
					while ((j >= 0) && (tokens.get(j).getNamedEntityType() == NamedEntityType.PERSON)) {
						person.insert(0, tokens.get(j).getWord() + " ");
						j--;
					}
					people.add(person.toString());
				}
			}
			// Each person killed all the other people
			for (String person1 : people) {
				for (String person2 : people) {
					if (person1.intern() != person2.intern()) {
						relations.add(new Relation(RelationName.Kill, person1, person2, sentenceID));
					}
				}
			}
			return relations;
		}
	}
	
	public static class LocatedInRuleComma implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.LocatedInRuleComma();
			return oldRule.applyRule(sentence);
		}
	}
	
	//looking for patterns like "X in Y"/ "X at Y" where X,Y are locations
	public static class LocatedInRuleLocInLocTokens implements Rule<SentenceWithDependenciesAndNER>{
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			@SuppressWarnings("unchecked")
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			List<SyntacticDependency> deps=sentence.getDependencies();
	
			for(int i=0;i<tokens.size()-2;i++){
				//searching location in location
				if((tokens.get(i).getNamedEntityType()==NamedEntityType.LOCATION) && (tokens.get(i+1).getWord().intern()=="in" || tokens.get(i+1).getWord().intern()=="at") && tokens.get(i+2).getNamedEntityType()==NamedEntityType.LOCATION){
	
					
						//preparing first argument
						String arg1=tokens.get(i).getWord();
						int j=i-1;
						if(tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION)
							continue;
					
						
						j=i+2;
						
						//preparing second argument
						String arg2=tokens.get(j).getWord();
						j++;
						if(tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION)
							continue;
						
						boolean foundDep=false;
						for(SyntacticDependency dep:deps){
							
							if(dep.getDependencyName()==DependencyName.prep_in && (dep.getGovernorToken()==tokens.get(i+2))){
	
								foundDep=true;
								break;
							}
						}
						
						if(!foundDep)
						relations.add(new Relation(RelationName.Located_In,arg1,arg2,sentenceID));
					}
				
				if(i+3<tokens.size() && tokens.get(i).getNamedEntityType()==NamedEntityType.LOCATION && tokens.get(i+1).getWord().intern()=="in" && tokens.get(i+2).getPos()==POS.JJ && tokens.get(i+3).getNamedEntityType()==NamedEntityType.LOCATION){
					
					String arg1=tokens.get(i).getWord();
					int j=i-1;
					
					while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION){
							arg1=tokens.get(j).getWord()+" "+arg1;
							j--;
					}
					
					j=i+3;
					String arg2=tokens.get(j).getWord();
					j++;
					if(tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION)
						continue;
					while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION){
						arg2+=" "+tokens.get(j).getWord();
						j++;
				}
					
				
					relations.add(new Relation(RelationName.Located_In,arg1,arg2,sentenceID));
				}
			
			}
			
			
			return relations;
		}
	}


	//looking for dependency "prep_in" between two locations
	public static class LocatedInRuleLocInLocDeps implements Rule<SentenceWithDependenciesAndNER>{
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			@SuppressWarnings("unchecked")
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			List<SyntacticDependency> deps=sentence.getDependencies();
	
			for(int i=0;i<deps.size();i++){
				TokenWithNER gov=(TokenWithNER)deps.get(i).getGovernorToken();
				TokenWithNER dependent=(TokenWithNER)deps.get(i).getDependentToken();
				
				//found dependency "prep_in" between two locations
				if((dependent.getNamedEntityType()==NamedEntityType.LOCATION  && gov.getNamedEntityType()==NamedEntityType.LOCATION && deps.get(i).getDependencyName()==DependencyName.prep_in)){
				
					int index=tokens.indexOf(gov);
				
					//preparing first argument
	
					String arg1=tokens.get(index).getWord();
					int j=index-1;
					while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION){
						arg1=tokens.get(j).getWord()+" "+arg1;
						j--;
					}
					
					index=tokens.indexOf(dependent);
					
					//preparing second argument
					String arg2=tokens.get(index).getWord();
					index++;
					while(index<tokens.size() && tokens.get(index).getNamedEntityType()==NamedEntityType.LOCATION ){
						arg2+=" "+tokens.get(index).getWord();
						index++;
						
					}
					relations.add(new Relation(RelationName.Located_In,arg1,arg2,sentenceID));
				}
			}
						
			
			return relations;
		}
	}

	//looking for X's Y where X,Y are locations
	public static class LocatedInRuleLocationsLocation implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
	
			for(int i=0;i<tokens.size()-2;i++){
				if(tokens.get(i).getNamedEntityType()==NamedEntityType.LOCATION && tokens.get(i).getPos()==POS.NNP && tokens.get(i+1).getWord().intern()=="'s"){
					if(tokens.get(i+2).getPos()==POS.NNP && (tokens.get(i+2).getNamedEntityType()==NamedEntityType.LOCATION || tokens.get(i+2).getNamedEntityType()==NamedEntityType.NOT_DEFINED)){
						
						//preparing first argument
						String arg1=tokens.get(i+2).getWord();
						int j=i+3;
						while(j<tokens.size() && tokens.get(j).getPos()==POS.NNP && (tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION || tokens.get(j).getNamedEntityType()==NamedEntityType.NOT_DEFINED)){
								arg1+=" "+tokens.get(j).getWord();
								j++;
						}
						
						if(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.ORGANIZATION)
							continue;
						
						//preparing second argument
						String arg2=tokens.get(i).getWord();
						j=i-1;
						while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION){
							arg2=tokens.get(j).getWord()+" "+arg2;
							j--;
						}
						relations.add(new Relation(RelationName.Located_In,arg1,arg2,sentenceID));
					}
				}
			}
			
			
			return relations;
		}
	}
	
	public static class OrgBasedRuleIn implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.OrgBasedRuleIn();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class OrgBasedRuleOf implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.OrgBasedRuleOf();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class OrgBasedRuleCapitalizedNNP implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.OrgBasedRuleCapitalizedNNP();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class OrgBasedRuleBasedIn implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.OrgBasedRuleBasedIn();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class OrgBasedRuleHeadquartesIn implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.OrgBasedRuleHeadquartesIn();
			return oldRule.applyRule(sentence);
		}
	}
	
	//looking for location which appears after organization
	public static class OrgBasedRuleLocationAfterOrganization implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			for (int i = 0; i < tokens.size() - 1; i++) {
				// Find an organization
				if ((tokens.get(i).getNamedEntityType() == NamedEntityType.ORGANIZATION) && (tokens.get(i + 1).getNamedEntityType() != NamedEntityType.ORGANIZATION)) {
					// Get the location
					int j = i + 1;
					while ((j < tokens.size()) && (tokens.get(j).getNamedEntityType() != NamedEntityType.LOCATION))
						j++;
					if (j == tokens.size())
						continue;
					int arg2Index=j;
					// Get the organization
					StringBuilder arg1 = new StringBuilder(tokens.get(i).getWord());
					j = i -1;
					while ((j >= 0) && (tokens.get(j).getNamedEntityType() == NamedEntityType.ORGANIZATION)) {
						arg1.insert(0, tokens.get(j).getWord() + " ");
						j--;
					}
					relations.add(new Relation(RelationName.OrgBased_In,arg1.toString(),tokens.get(arg2Index).getWord(),sentenceID));
				}
			}
			return relations;
		}
	}
	
	//looking for location which appears near organization
	public static class OrgBasedRuleLocationAroundOraganization implements Rule<SentenceWithDependenciesAndNER> {
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			for (int i = 0; i < tokens.size(); i++) {
				// Find an organization
				if ((tokens.get(i).getNamedEntityType() == NamedEntityType.ORGANIZATION) && ((i == tokens.size() - 1) || (tokens.get(i + 1).getNamedEntityType() != NamedEntityType.ORGANIZATION))) {
					// Get the organization
					StringBuilder arg1 = new StringBuilder(tokens.get(i).getWord());
					int j = i - 1;
					while ((j >= 0) && (tokens.get(j).getNamedEntityType() == NamedEntityType.ORGANIZATION)) {
						arg1.insert(0, tokens.get(j).getWord() + " ");
						j--;
					}
					// Get the locations around the organization
					int start = i - 5 >= 0 ? i - 5 : 0;
					int end = i + 5 < tokens.size() ? i + 6 : tokens.size();
					j = start;
					while (j < end) {
						if (tokens.get(j).getNamedEntityType() == NamedEntityType.LOCATION) {
							StringBuilder arg2 = new StringBuilder(tokens.get(j).getWord());
							j++;
							while ((j < end) && (tokens.get(j).getNamedEntityType() == NamedEntityType.LOCATION)) {
								arg2.append(" " + tokens.get(j).getWord());
								j++;
							}
							relations.add(new Relation(RelationName.OrgBased_In, arg1.toString(), arg2.toString(), sentenceID));
						}
						j++;
					}
				}
			}
			return relations;
		}
	}
	
	public static class WorkForRuleBrackets implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.WorkForRuleBrackets();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class WorkForRuleOfThe implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.WorkForRuleOfThe();
			return oldRule.applyRule(sentence);
		}
	}
	
	//finding patterns like "X, -profession- of Y," or "X, -profession- from Y,"
	public static class WorkForRuleOfFixed implements Rule<SentenceWithDependenciesAndNER> {
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<TokenWithNER> tokens=(List<TokenWithNER>) sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			
			List<String> professions=new ArrayList<String>();
			professions.add("spokesman");
			professions.add("placekicker");
			professions.add("teacher");
			professions.add("Capt.");
			professions.add("Secretary-General");
			professions.add("official");
			professions.add("professor");
			professions.add("Judge");
			professions.add("chairman");
			professions.add("officer");
			professions.add("employee");
			professions.add("attorney");
			professions.add("publisher");
			professions.add("member");
			professions.add("director");
			professions.add("shearer");
			professions.add("head");
			professions.add("electrician");
			professions.add("executive");
			professions.add("president");
			professions.add("manager");
			professions.add("spokeswoman");
			professions.add("columnist");
			professions.add("owner");
			
			List<String> forbiddenArguments=new ArrayList<String>();
			forbiddenArguments.add("January");
			forbiddenArguments.add("February");
			forbiddenArguments.add("March");
			forbiddenArguments.add("April");
			forbiddenArguments.add("May");
			forbiddenArguments.add("June");
			forbiddenArguments.add("July");
			forbiddenArguments.add("August");
			forbiddenArguments.add("September");
			forbiddenArguments.add("October");
			forbiddenArguments.add("December");
			forbiddenArguments.add("Jan.");
			forbiddenArguments.add("Feb.");
			forbiddenArguments.add("August");
			forbiddenArguments.add("Sept.");
			forbiddenArguments.add("Oct.");
			forbiddenArguments.add("Dec.");
			forbiddenArguments.add("Sunday");
			forbiddenArguments.add("Monday");
			forbiddenArguments.add("Tuesday");
			forbiddenArguments.add("Wednesday");
			forbiddenArguments.add("Thursday");
			forbiddenArguments.add("Friday");
			forbiddenArguments.add("Saturday");
			forbiddenArguments.add("Inc");
			
			for (int i = 0; i < tokens.size(); i++) {
				if(professions.contains(tokens.get(i).getWord())){
					int j,k;

					
					//looking for a comma before the profession
					for(j=i;j>=0;j--){
						if(tokens.get(j).getWord().intern() == ",")
							break;
					}
					
					//no comma found
					if(j<0)
						continue;
			
					//looking for comma or period after the profession
					for(k=i+1;k<tokens.size();k++){
						if(tokens.get(k).getWord().intern() == "," || tokens.get(k).getWord().intern() == ".")
							break;
					}
					
					//no comma found
					if(k==tokens.size())
						continue;
					
					int jj;
					
					//looking for "of" or "from" between the commas
					for(jj=i;jj<k;jj++)
						if(tokens.get(jj).getLemma().intern() == "of" || tokens.get(jj).getLemma().intern() == "for")
							break;
					
					//no "of" or "from" found
					if(jj==k)
						continue;
					
			
					
					j--;
					
					//looking for NNP before the first comma
					while ((j >= 0) && (tokens.get(j).getLemma().intern() != ",") && (((tokens.get(j).getPos() != POS.NNP) && (tokens.get(j).getPos() != POS.NNPS)) || tokens.get(j).getNamedEntityType()!=NamedEntityType.PERSON))
						j--;
					
					//if we saw another comma before the NNP, or haven't found NNP
					if ((j == -1) || (tokens.get(j).getLemma().intern() == ","))
						continue;
					
					String arg1=tokens.get(j).getWord();
					j--;
					boolean forbidden=false;
					
					//preparing first argument
					while ((j >= 0) && ((tokens.get(j).getPos() == POS.NNP && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON) || (tokens.get(j).getPos() == POS.JJ && tokens.get(j).getWord().charAt(0)>='A' && tokens.get(j).getWord().charAt(0)<='Z') || (tokens.get(j).getPos() == POS.NNPS))) {
						if(forbiddenArguments.contains(tokens.get(j).getWord().intern())){
							forbidden=true;
							break;
						}
						arg1=tokens.get(j).getWord() + " "+arg1;
						j--;
					}
					
					if(forbidden)
						continue;
					
					int m;
					for(m=i+1;m<k;m++){
						if(tokens.get(m).getPos() == POS.NNP || tokens.get(m).getPos() == POS.NNPS || (tokens.get(m).getPos() == POS.JJ && tokens.get(m).getWord().charAt(0)>='A' && tokens.get(m).getWord().charAt(0)<='Z'))
							if(tokens.get(m).getNamedEntityType()==NamedEntityType.ORGANIZATION)
							break;
					}
					
					if(m==k)
						continue;
					
					String arg2=tokens.get(m).getWord();
					m++;
					boolean isOrg=true;
					//preparing second argument
					while(m<k && (tokens.get(m).getLemma().intern() == "of" || (tokens.get(m).getLemma().intern() == "on")|| (tokens.get(m).getPos() == POS.NNP || tokens.get(m).getPos() == POS.NNPS || (tokens.get(m).getPos() == POS.JJ && tokens.get(m).getWord().charAt(0)>='A' && tokens.get(m).getWord().charAt(0)<='Z')))){
						if(tokens.get(m).getNamedEntityType()==NamedEntityType.PERSON){
							isOrg=false;
							break;
						}
							
						arg2+=" "+tokens.get(m).getWord();
						m++;
					}
					
					if(!isOrg)
						continue;
					if (forbiddenArguments.contains(arg1) || forbiddenArguments.contains(arg2))
						continue;
					set.add(new Relation(Relation.RelationName.Work_For,arg1,arg2,sentenceID));
					
				}
			}
			return set;
		}
	}
	
	//find patterns like "X, who -work_verb- ... Y"
	public static class WorkForRuleWhoWorksFixed implements Rule<SentenceWithDependenciesAndNER> {
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<TokenWithNER> tokens=(List<TokenWithNER>) sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			//list of work related verbs
			List<String> workVerbs=new ArrayList<String>();
			workVerbs.add("direct");
			workVerbs.add("head");
			workVerbs.add("serve");
			workVerbs.add("star");
			workVerbs.add("manage");
			for(int i=0;i<tokens.size()-2;i++){
				
				if(tokens.get(i).getPos()==POS.NNP && tokens.get(i).getNamedEntityType()==NamedEntityType.PERSON && tokens.get(i+1).getLemma().intern()==","){
					int j;
					for(j=i+1;j<tokens.size()-1;j++){
						
						//found one of the verbs
						if(tokens.get(j).getLemma().intern()=="who" && workVerbs.contains((tokens.get(j+1).getLemma()))){
							break;
						}
					}
					if(j>=tokens.size()-1)
						continue;
					
					String arg1=tokens.get(i).getWord();
					int k=i-1;

					//preparing first argument
					while(k>=0 && tokens.get(k).getPos() == POS.NNP && tokens.get(k).getNamedEntityType()==NamedEntityType.PERSON ){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
					
					
					for(k=j+2;k<tokens.size();k++){
						if(tokens.get(k).getPos()==POS.NNP && tokens.get(k).getNamedEntityType()==NamedEntityType.ORGANIZATION)
							break;
					}
					
					if(k==tokens.size())
						continue;
					String arg2=tokens.get(k).getWord();
					k++;
					
					//preparing second argument
					while(k<tokens.size() && tokens.get(k).getNamedEntityType()==NamedEntityType.ORGANIZATION && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS || tokens.get(k).getLemma().intern()=="of" || tokens.get(k).getLemma().intern()=="the")){
						arg2+=" "+tokens.get(k).getWord();
						k++;
					}
					
					set.add(new Relation(Relation.RelationName.Work_For,arg1,arg2,sentenceID));
				}
						
			}
				
			
			
			return set;
		}
	}
	
	//finding patterns like "
	public static class WorkForRuleProfessionFixed implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			List<TokenWithNER> tokens=(List<TokenWithNER>) sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			//preparing list of professions
			List<String> professions=new ArrayList<String>();
			professions.add("spokesman");
			professions.add("placekicker");
			professions.add("teacher");
			professions.add("Capt.");
			professions.add("Secretary-General");
			professions.add("official");
			professions.add("professor");
			professions.add("Judge");
			professions.add("chairman");
			professions.add("officer");
			professions.add("Officer");
			professions.add("employee");
			professions.add("attorney");
			professions.add("Administrator");
			professions.add("spokeswoman");
			professions.add("Director");
			for (int i = 1; i < tokens.size(); i++) {
				
				
				//we found one of the professions	
				if (professions.contains(tokens.get(i).getLemma()) && tokens.get(i-1).getWord().intern()!="and") {
					int j = i - 1;
					while ((j >= 0) && (tokens.get(j).getLemma().intern() != ",") &&(tokens.get(j).getNamedEntityType()!=NamedEntityType.ORGANIZATION || (tokens.get(j).getPos() != POS.NNP) && (tokens.get(j).getPos() != POS.NNPS)))
						j--;
					if ((j == -1) || (tokens.get(j).getLemma().intern() == ","))
						continue;
					
					//preparing second argument
					StringBuilder arg2 = new StringBuilder(tokens.get(j).getLemma());
					j--;
					while ((j >= 0) && tokens.get(j).getNamedEntityType()==NamedEntityType.ORGANIZATION &&((tokens.get(j).getPos() == POS.NNP) || (tokens.get(j).getPos() == POS.JJ && tokens.get(j).getWord().charAt(0)>='A' && tokens.get(j).getWord().charAt(0)<='Z') || (tokens.get(j).getPos() == POS.NNPS) || (tokens.get(j).getLemma().intern() == "of") )) {
						arg2.insert(0, tokens.get(j).getWord() + " ");
						j--;
					}
					j = i + 1;
	
					//no NNP
					if ((tokens.get(j).getPos() != POS.NNP) && (tokens.get(j).getPos() != POS.NNPS))
						continue;
					
					//preparing first argument
					StringBuilder arg1 = new StringBuilder(tokens.get(j).getLemma());
					j++;
					while ((j < tokens.size()) && ((tokens.get(j).getPos() == POS.NNP) || (tokens.get(j).getPos() == POS.NNPS) || (tokens.get(j).getWord().intern()=="de") || (tokens.get(j).getWord().intern()=="`"))) {
						if(tokens.get(j).getWord().intern()=="`")
							arg1.append(" "+"'");
						else if(tokens.get(j-1).getWord().intern()=="`")
							arg1.append(tokens.get(j).getWord());
						else
							arg1.append(" " + tokens.get(j).getWord());
						j++;
					
					}
					set.add(new Relation(Relation.RelationName.Work_For,arg1.toString(),arg2.toString(),sentenceID));
				}
			}
			return set;
		}
	}

	//find patterns like "X...from Y" where X is person and Y is organization
	public static class WorkForRulePersonForOrg implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			for (int i = 0; i < tokens.size() - 1; i++) {
				
				//found person
				if ((tokens.get(i).getNamedEntityType() == NamedEntityType.PERSON) && (tokens.get(i + 1).getNamedEntityType() != NamedEntityType.PERSON)) {
					int j = i + 1;
					
					//looking for "for org"
					while ((j < tokens.size()-1) && !(tokens.get(j+1).getNamedEntityType() == NamedEntityType.ORGANIZATION && (tokens.get(j).getWord().intern()=="for" || tokens.get(j).getWord().intern()=="with")))
						j++;
					
					//didn't find of found too far away
					if (j >= tokens.size()-1 || j-i>7)
						continue;
					
					int arg2Index=j+1;
					
					//preparing second argument
					
					String arg2=tokens.get(arg2Index).getWord();
					arg2Index++;
					while(arg2Index<tokens.size() && tokens.get(arg2Index).getNamedEntityType()==NamedEntityType.ORGANIZATION){
						arg2+=" "+tokens.get(arg2Index).getWord();
						arg2Index++;
					}
					
					//preparing first argument
					StringBuilder arg1 = new StringBuilder(tokens.get(i).getWord());
					j = i -1;
					
					while ((j >= 0) && (tokens.get(j).getNamedEntityType() == NamedEntityType.PERSON)) {
						arg1.insert(0, tokens.get(j).getWord() + " ");
						j--;
					}
					relations.add(new Relation(RelationName.Work_For,arg1.toString(),arg2,sentenceID));
				}
			}
			return relations;
		}
	}
	
	//looking for patterns like "X... of Y" where X is person and Y is organization
	public static class WorkForRulePersonOfOrg implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			
			//searching the tokens
			for (int i = 0; i < tokens.size() - 1; i++) {
				
				//found person
				if ((tokens.get(i).getNamedEntityType() == NamedEntityType.PERSON) && (tokens.get(i + 1).getNamedEntityType() != NamedEntityType.PERSON)) {
					int j = i + 1;
					while ((j < tokens.size()-1) && !(tokens.get(j+1).getNamedEntityType() == NamedEntityType.ORGANIZATION && (tokens.get(j).getWord().intern()=="of")))
						j++;
					
					//didn't find "of organization" or found too far away
					if (j >= tokens.size()-1 || j-i>3)
						continue;
					
					int arg2Index=j+1;
					
					//preparing second argument
					String arg2=tokens.get(arg2Index).getWord();
					arg2Index++;
					while(arg2Index<tokens.size() && tokens.get(arg2Index).getNamedEntityType()==NamedEntityType.ORGANIZATION){
						arg2+=" "+tokens.get(arg2Index).getWord();
						arg2Index++;
					}
					
					
					//preparing first argument
					StringBuilder arg1 = new StringBuilder(tokens.get(i).getWord());
					j = i -1;
					
					while ((j >= 0) && (tokens.get(j).getNamedEntityType() == NamedEntityType.PERSON)) {
						arg1.insert(0, tokens.get(j).getWord() + " ");
						j--;
					}
					relations.add(new Relation(RelationName.Work_For,arg1.toString(),arg2,sentenceID));
				}
			}
			return relations;
		}
	}
	
	//looking for an appos dependency where the governor is a person, and then searching another dependency whose governor is the dependent
	public static class WorkForRulePersonAppos implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			List<SyntacticDependency> deps=sentence.getDependencies();

			//searching the dependencies
			for(int i=0;i<deps.size();i++){
				TokenWithNER gov=(TokenWithNER)deps.get(i).getGovernorToken();
				
				//found an appos dependency whose governor is person
				if(gov.getNamedEntityType()==NamedEntityType.PERSON && deps.get(i).getDependencyName()==DependencyName.appos){
					
					//looking for another dependency whose governor is deps.get(i) dependent
					for(SyntacticDependency dep:deps){
						
						if(dep.getGovernorToken()==deps.get(i).getDependentToken()){
					
							TokenWithNER dependent2=(TokenWithNER)dep.getDependentToken();
							
							//checking if the dependent is organization
							if(dependent2.getNamedEntityType()==NamedEntityType.ORGANIZATION){
								
								int index=tokens.indexOf(dependent2);
								//preparing second argument
								String arg2=dependent2.getWord();
								int j=index+1;
								while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.ORGANIZATION){
									arg2+=" "+tokens.get(j).getWord();
									j++;
								}
								j=index-1;
								while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.ORGANIZATION){
									arg2=tokens.get(j).getWord()+" "+arg2;
									j--;
								}
								
								//preparing first argument
								String arg1=gov.getWord();
								index=tokens.indexOf(gov);
								j=index-1;
								while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON){
									arg1=tokens.get(j).getWord()+" "+arg1;
									j--;
								}
									
								relations.add(new Relation(RelationName.Work_For,arg1,arg2,sentenceID));
								break;
							}
						}
					}
				}
			}
				
			return relations;
		}
	}
	
	
	//finding patterns like "Y's X" where X is a person and Y is an organization
	public static class WorkForRuleOrganizationsPerson implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			//searching the tokens
			for(int i=0;i<tokens.size()-2;i++){
				
				//found organization ,afterwards "'s", afterwards person
				if(tokens.get(i).getNamedEntityType()==NamedEntityType.ORGANIZATION && tokens.get(i+1).getWord().intern()=="'s"){
					if(tokens.get(i+2).getNamedEntityType()==NamedEntityType.PERSON){
						
						//preparing first argument
						String arg1=tokens.get(i+2).getWord();
						int j=i+3;
						while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON){
								arg1+=" "+tokens.get(j).getWord();
								j++;
						}
						
						//preparing second argument
						String arg2=tokens.get(i).getWord();
						j=i-1;
						while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.ORGANIZATION){
							arg2=tokens.get(j).getWord()+" "+arg2;
							j--;
						}
						relations.add(new Relation(RelationName.Work_For,arg1,arg2,sentenceID));
					}
				}
			}
			
			
			return relations;
		}
	}
	

	//looking for "Y employee" where Y is organization (looking for dependency between employee and organization) and then looking for person
	public static class WorkForRuleOrganizationsEmployee implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			List<SyntacticDependency> deps=sentence.getDependencies();

			//searching the dependencies
			for(int i=0;i<deps.size();i++){
				TokenWithNER gov=(TokenWithNER)deps.get(i).getGovernorToken();
				TokenWithNER dependent=(TokenWithNER)deps.get(i).getDependentToken();
				//if the governor is "employee" and the dependent is organization
				if((gov.getWord().intern()=="employee" || gov.getWord().intern()=="worker") && (dependent.getNamedEntityType()==NamedEntityType.ORGANIZATION ||dependent.getNamedEntityType()==NamedEntityType.LOCATION || dependent.getPos()==POS.NNP)){
					
					int index=tokens.indexOf(gov);
					//looking for person after the organization
					while(index<tokens.size() &&  tokens.get(index).getNamedEntityType()!=NamedEntityType.PERSON)
						index++;
					
				
					//haven't found person after
					if(index==tokens.size()){
						
						int depIndex=tokens.indexOf(dependent);
						int j;
						//looking for person before the organization
						for(j=depIndex;j>=0;j--)
							if(tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON)
								break;
						
						//haven't found
						if(j<0)
							continue;
						
						//preparing first argument
						String arg1=tokens.get(j).getWord();
						j--;
						while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON){
							arg1=tokens.get(j).getWord()+" "+arg1;
							j--;
						}
						relations.add(new Relation(RelationName.Work_For,arg1,dependent.getWord(),sentenceID));
						continue;
						
					}
					
					//preparing first argument
					String arg1=tokens.get(index).getWord();
					index++;
					while(index<tokens.size() && tokens.get(index).getNamedEntityType()==NamedEntityType.PERSON ){
						arg1+=" "+tokens.get(index).getWord();
						index++;
						
					}
					relations.add(new Relation(RelationName.Work_For,arg1,dependent.getWord(),sentenceID));
				}
			}
						
			
			return relations;
		}
	}

	//find patterns like "X...of the Y" where X is person and Y is organization
	public static class WorkForRulePersonOfTheOrg implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
	
			//searching the tokens
			for(int i=0;i<tokens.size()-2;i++){
				
				//found "of the org"
				if(tokens.get(i).getWord().intern()=="of" && tokens.get(i+1).getWord().intern()=="the" && tokens.get(i+2).getNamedEntityType()==NamedEntityType.ORGANIZATION){
					
						String arg2=tokens.get(i+2).getWord();
						int j=i+3;
						
						//preparing second argument
						while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.ORGANIZATION && tokens.get(j).getPos()==POS.NNP){
								arg2+=" "+tokens.get(j).getWord();
								j++;
								
						}
						
						//didn't find organization
						if(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.ORGANIZATION)
							continue;
						
						//looking for person before
						for(j=i-1;j>=0;j--)
							if(tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON)
								break;
							
						//didn't find person or too far away
						if(j<0 || i-j>2)
							continue;
						
						//preparing first argument
						String arg1=tokens.get(j).getWord();
						j--;
						while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON){
							arg1=tokens.get(j).getWord()+" "+arg1;
							j--;
						}
						relations.add(new Relation(RelationName.Work_For,arg1,arg2,sentenceID));
					}
				
			}
			
			
			return relations;
		}
	}
	

	//looking for patterns like "X's Y" where X is a person and Y is an organization
	public static class WorkForRulePersonsOrganization implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
	
			for(int i=0;i<tokens.size()-2;i++){
				
				//found person , 's, org
				if(tokens.get(i).getNamedEntityType()==NamedEntityType.PERSON && tokens.get(i+1).getWord().intern()=="'s"){
					if(tokens.get(i+2).getNamedEntityType()==NamedEntityType.ORGANIZATION){
						String arg2=tokens.get(i+2).getWord();
						int j=i+3;
						
						//preparing second argument
						while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.ORGANIZATION){
								arg2+=" "+tokens.get(j).getWord();
								j++;
						}
						
						//preparing first argument
						String arg1=tokens.get(i).getWord();
						j=i-1;
						while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON){
							arg1=tokens.get(j).getWord()+" "+arg1;
							j--;
						}
						relations.add(new Relation(RelationName.Work_For,arg1,arg2,sentenceID));
					}
				}
			}
			return relations;
		}
	}
	
	public static class LiveInRuleSomeonesHome implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.LiveInRuleSomeonesHome();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class LiveInRuleProfession implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.LiveInRuleProfession();
			return oldRule.applyRule(sentence);
		}
	}
	
	public static class LiveInCommaAndAge implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			Rule<Sentence> oldRule = new Ex2Configuration.LiveInCommaAndAge();
			return oldRule.applyRule(sentence);
		}
	}
	
	//find patterns like "X...home in...Y"
	public static class LiveInRuleHomeInFixed implements Rule<SentenceWithDependenciesAndNER>{
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			@SuppressWarnings("unchecked")
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			//searching through the tokens the word "home"
			for(int i=0;i<tokens.size()-1;i++){
				
				if(tokens.get(i).getLemma().intern() == "home" || tokens.get(i).getLemma().intern() == "office"){
					
					String arg2="";
					
					//searching for the word "in"
					for(int j=i;j<tokens.size()-1;j++){
						if(tokens.get(j).getLemma().intern() == "in"){
							int k=j+1;
							while(k<tokens.size() && (tokens.get(k).getPos() != POS.NNP || tokens.get(k).getNamedEntityType()!=NamedEntityType.LOCATION)){
								
								k++;
							}
							
							if(k==tokens.size())
								continue;
							arg2=tokens.get(k).getWord();
							k++;
							//preparing second argument
							while(k<tokens.size() && tokens.get(k).getPos() == POS.NNP && tokens.get(k).getNamedEntityType()==NamedEntityType.LOCATION){
								arg2+=" "+tokens.get(k).getWord();
								k++;
							}
							
						}
					}
					String arg1="";
					int k=i-1;
					
					//looking for NNP phrase before "home"
					while(k>=0 && (tokens.get(k).getPos() != POS.NNP || tokens.get(k).getNamedEntityType()!=NamedEntityType.PERSON)){
						
						k--;
					}
					if(k<0)
						continue;
					
					arg1=tokens.get(k).getWord();
					k--;
					//preparing first argument
					while(k>=0 && tokens.get(k).getPos() == POS.NNP && tokens.get(k).getNamedEntityType()==NamedEntityType.PERSON){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
	
					//if the arguments aren't empty
					if(arg1.intern()!="" && arg2.intern()!="")
						set.add(new Relation(Relation.RelationName.Live_In,arg1,arg2,sentenceID));
						
					}
				}
			
			return set;
		}
	}

	//finding patterns like "Y -profession- X" or "Y's -profession- X"
	public static class LiveInPlaceProfessionsFixed implements Rule<SentenceWithDependenciesAndNER> {
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> set = new LinkedList<Relation>();
			
			@SuppressWarnings("unchecked")
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID=tokens.get(0).getSentenceId();
			
			//preparing list of professions
			List<String> professions=new ArrayList<String>();
			professions.add("ambassador");
			professions.add("Ambassador");
			professions.add("deputy");
			professions.add("Sheriff");
			professions.add("Judge");
			professions.add("Gov.");
			professions.add("soprano");
			professions.add("artist");
			professions.add("Sen.");
			professions.add("businessman");
			professions.add("Lt.");
			professions.add("Attorney");
			professions.add("President");
			//professions.add("G.");
			professions.add("governor");
			professions.add("superintendent");
			professions.add("Secretary");
			professions.add("surgeon");
			professions.add("Mayor");
			professions.add("lady");
			professions.add("historian");
			professions.add("Commissioner");
			professions.add("political");
			professions.add("Premier");
			//professions.add("Foreign");
			List<String> forbiddenArgs=new ArrayList<String>();
			//preparing list of forbidden arguments
			forbiddenArgs.add("Sunday");
			forbiddenArgs.add("Monday");
			forbiddenArgs.add("Tuesday");
			forbiddenArgs.add("Wednesday");
			forbiddenArgs.add("Thursday");
			forbiddenArgs.add("Friday");
			forbiddenArgs.add("Saturday");
			
			for(int i=1;i<tokens.size();i++){
				
				//checking if we found pattern "Y -profession- X"
				if(((tokens.get(i-1).getPos()==POS.NNP  || tokens.get(i-1).getPos()==POS.NNPS ) && professions.contains(tokens.get(i).getLemma())) ||
						( i-2>=0 && (tokens.get(i-2).getPos()==POS.NNP  || tokens.get(i-2).getPos()==POS.NNPS)&& (tokens.get(i-1).getPos()==POS.JJ || tokens.get(i-1).getPos()==POS.NN) && professions.contains(tokens.get(i).getLemma()))){
				
					String arg1;
					int k;
					if(tokens.get(i-1).getPos()!=POS.JJ && tokens.get(i-1).getPos()!=POS.NN){
						arg1=tokens.get(i-1).getWord();
						k=i-2;
					}
					else{
						arg1=tokens.get(i-2).getWord();
						k=i-3;
					}
					
					//preparing first argument (NNP phrase before the profession)
					while(k>=0 && (tokens.get(k).getPos() == POS.NNP || tokens.get(k).getPos() == POS.NNPS )){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
		
					
					int j;
					
					//searching NNP after the profession
					for(j=i+1;j<tokens.size();j++)
						if(tokens.get(j).getPos()==POS.NNP  && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON)
							break;
					
					//if NNP wasn't found or too far away
					if(j==tokens.size() || j-i>2)
						continue;
					
					
					
					String arg2=tokens.get(j).getWord();
					k=j+1;
				
					//preparing second argument
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)  && tokens.get(k).getNamedEntityType()==NamedEntityType.PERSON){
						arg2+=" "+tokens.get(k).getWord();
						k++;	
					}
					
					if(arg1.contains("U.S"))
						arg1="U.S";
					
					if(forbiddenArgs.contains(arg2) || forbiddenArgs.contains(arg1))
						continue;
					set.add(new Relation(Relation.RelationName.Live_In,arg2,arg1,sentenceID));
			
				}
			
				
				//checking if we found pattern "Y's -profession- X"
				if((i-2>=0 && (tokens.get(i-2).getPos()==POS.NNP  || tokens.get(i-2).getPos()==POS.NNPS)&& tokens.get(i-1).getLemma().intern()=="'s" && professions.contains(tokens.get(i).getLemma())) ||
						 
							(i-3>=0 && (tokens.get(i-3).getPos()==POS.NNP  || tokens.get(i-3).getPos()==POS.NNPS) && tokens.get(i-2).getLemma().intern()=="'s")&& tokens.get(i-1).getPos()==POS.JJ && professions.contains(tokens.get(i).getLemma())){
					
					
					
					String arg1;
					int k;
					
					if(tokens.get(i-1).getPos()!=POS.JJ){
						arg1=tokens.get(i-2).getWord();
						k=i-3;
					}
					else
					{
						arg1=tokens.get(i-3).getWord();
						k=i-4;
					}
					
					//preparing first argument (NNP phrase before the profession)
					while(k>=0 && (tokens.get(k).getPos() == POS.NNP || tokens.get(k).getPos() == POS.NNPS ) && tokens.get(k).getNamedEntityType()==NamedEntityType.PERSON ){
						arg1=tokens.get(k).getWord()+" "+arg1;
						k--;
					}
					
		
						
					int j;
					
					//searching NNP after the profession
					for(j=i+1;j<tokens.size();j++)
						if(tokens.get(j).getPos()==POS.NNP  && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON)
							break;
					
					//if NNP wasn't found or too far away
					if(j==tokens.size() || j-i>3)
						continue;
					
					
					
					String arg2=tokens.get(j).getWord();
					k=j+1;
				
					//preparing second argument
					while(k<tokens.size() && (tokens.get(k).getPos()==POS.NNP || tokens.get(k).getPos()==POS.NNPS)  && tokens.get(k).getNamedEntityType()==NamedEntityType.PERSON){
						arg2+=" "+tokens.get(k).getWord();
						k++;	
					}
	
					if(forbiddenArgs.contains(arg2) || forbiddenArgs.contains(arg1))
						continue;
					set.add(new Relation(Relation.RelationName.Live_In,arg2,arg1,sentenceID));
			
				}
			
			}
			
			return set;
		}
	
	}
	
	//looking for location which appears after person
	public static class LiveInRuleLocationAfterPerson implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			for (int i = 0; i < tokens.size() - 1; i++) {
				//found person
				if ((tokens.get(i).getNamedEntityType() == NamedEntityType.PERSON) && (tokens.get(i + 1).getNamedEntityType() != NamedEntityType.PERSON)) {
					int j = i + 1;
					
					//looking for location
					while ((j < tokens.size()) && (tokens.get(j).getNamedEntityType() != NamedEntityType.LOCATION))
						j++;
					
					//didn't find location
					if (j == tokens.size())
						continue;
					
					if((tokens.get(j-1).getWord().intern()!="of") || j-i>2)
						continue;
					
					//preparing first argument
					int arg2Index=j;
					StringBuilder arg1 = new StringBuilder(tokens.get(i).getWord());
					j = i -1;
					while ((j >= 0) && (tokens.get(j).getNamedEntityType() == NamedEntityType.PERSON)) {
						arg1.insert(0, tokens.get(j).getWord() + " ");
						j--;
					}
					relations.add(new Relation(RelationName.Live_In,arg1.toString(),tokens.get(arg2Index).getWord(),sentenceID));
				}
			}
			return relations;
		}
	}

	//looking for dependencies between a person and location
	public static class LiveInRuleDepPersonLoc implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			
			//getting sentence ID
			String sentenceID = tokens.get(0).getSentenceId();
			List<SyntacticDependency> deps=sentence.getDependencies();
	
			//looking for a dependency of type "dep" between a person and a location
			for(int i=0;i<deps.size();i++){
				TokenWithNER gov=(TokenWithNER)deps.get(i).getGovernorToken();
				TokenWithNER dependent=(TokenWithNER)deps.get(i).getDependentToken();
				
				//checking if the dependent is a person and the governor is a location
				if(deps.get(i).getDependencyName()==DependencyName.dep && dependent.getNamedEntityType()==NamedEntityType.PERSON && gov.getNamedEntityType()==NamedEntityType.LOCATION){
					
					int index=tokens.indexOf(dependent);
					String arg1=dependent.getWord();
					index--;
					
					//preparing first argument(the person's full name)
					while(index>=0 && tokens.get(index).getNamedEntityType()==NamedEntityType.PERSON){
						arg1=tokens.get(index).getWord()+" "+arg1;
						index--;
					}
				
					relations.add(new Relation(RelationName.Live_In,arg1,gov.getWord(),sentenceID));
				}
			}
			return relations;
		}
	}

	//looking for patterns like "President X, ...Y" where Y is a location
	public static class LiveInRulePresidentsLocation implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
	
			for(int i=1;i<tokens.size()-2;i++){
				if(tokens.get(i).getNamedEntityType()==NamedEntityType.PERSON && tokens.get(i-1).getWord().intern()=="President"){
	
	
					//preparing first argument (full name of the president)
					String arg1=tokens.get(i).getWord();
					int j=i+1;
					while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON){
						arg1+=" "+tokens.get(j).getWord();
						j++;
					}
	
					//searching the location after the president's name
					while(j<tokens.size() && tokens.get(j).getNamedEntityType()!=NamedEntityType.LOCATION)
						j++;
	
					//no location found
					if(j==tokens.size())
						continue;
	
					//preparing second argument
					String arg2=tokens.get(j).getWord();
					j++;
					//finding full name of location (president's country)
					while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION){
						arg2+=" "+tokens.get(j).getWord();
						j++;
					}
					relations.add(new Relation(RelationName.Live_In,arg1,arg2,sentenceID));
					}
				
			}
			
			
			return relations;
		}
	}


	//find patterns like Y's X where Y is a location and X is a person
	public static class LiveInRuleLocationsPerson implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			
			//getting list of tokens and sentence ID
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
	
			//running through all tokens
			for(int i=0;i<tokens.size()-2;i++){
				
				//looking for a location with 's afterwards
				if(tokens.get(i).getNamedEntityType()==NamedEntityType.LOCATION && tokens.get(i+1).getWord().intern()=="'s"){
					
					//checking if there is a person after the 's
					if(tokens.get(i+2).getNamedEntityType()==NamedEntityType.PERSON){
						
						String arg2=tokens.get(i+2).getWord();
						int j=i+3;
						//preparing first argument (person)
						while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON){
								arg2+=" "+tokens.get(j).getWord();
								j++;
						}
						
						String arg1=tokens.get(i).getWord();
						j=i-1;
						
						//preparing second argument (location)
						while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION){
							arg1=tokens.get(j).getWord()+" "+arg1;
							j--;
						}
						relations.add(new Relation(RelationName.Live_In,arg2,arg1,sentenceID));
					}
				}
			}
			return relations;
		}
	}

	//looking for an appos dependency where the governor is a person, and then searching another dependency whose governor is the dependent
	public static class LiveInRulePersonAppos implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			
			//getting list of tokens and dependencies
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			List<SyntacticDependency> deps=sentence.getDependencies();
	
			//searching the dependencies
			for(int i=0;i<deps.size();i++){
				
				TokenWithNER gov=(TokenWithNER)deps.get(i).getGovernorToken();
				//found an appos dependency whose governor is a person
				if(gov.getNamedEntityType()==NamedEntityType.PERSON && deps.get(i).getDependencyName()==DependencyName.appos){
					
					//looking for another dependency where governor is this dependency's dependent
					for(SyntacticDependency dep:deps){
						
						if(dep.getGovernorToken()==deps.get(i).getDependentToken()){
					
							TokenWithNER dependent2=(TokenWithNER)dep.getDependentToken();
							
							//if the the dependent of the new dependenct is a location, we realize it's related to the person
							if(dependent2.getNamedEntityType()==NamedEntityType.LOCATION){
								
								int index=tokens.indexOf(dependent2);
								
								//preparing second argument (full location)
								String arg2=dependent2.getWord();
								int j=index+1;
								while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION){
									arg2+=" "+tokens.get(j).getWord();
									j++;
								}
								j=index-1;
								while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION){
									arg2=tokens.get(j).getWord()+" "+arg2;
									j--;
								}
								
								//preparing first argument (full name of the person)
								String arg1=gov.getWord();
								index=tokens.indexOf(gov);
								j=index-1;
								while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON){
									arg1=tokens.get(j).getWord()+" "+arg1;
									j--;
								}
									
								relations.add(new Relation(RelationName.Live_In,arg1,arg2,sentenceID));
								break;
							}
						}
					}
				}
			}
			return relations;
		}
	}

	//find patterns like "X ...of Y" where X is a person and Y is a location
	public static class LiveInRulePersonOfLoc implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			
			//searching the tokens
			for (int i = 0; i < tokens.size() - 1; i++) {
				
				//found a person
				if ((tokens.get(i).getNamedEntityType() == NamedEntityType.PERSON) && (tokens.get(i + 1).getNamedEntityType() != NamedEntityType.PERSON)) {
					
					int j = i + 1;
					//looking for "of Y" where Y is a location
					while ((j < tokens.size()-1) && !(tokens.get(j+1).getNamedEntityType() == NamedEntityType.LOCATION && (tokens.get(j).getWord().intern()=="of")))
						j++;
					
					//didn't find or found too far away
					if (j >= tokens.size()-1 || j-i>3)
						continue;
					
					int arg2Index=j+1;
					
					//preparing second argument (the location)
					String arg2=tokens.get(arg2Index).getWord();
					arg2Index++;
					while(arg2Index<tokens.size() && tokens.get(arg2Index).getNamedEntityType()==NamedEntityType.LOCATION){
						arg2+=" "+tokens.get(arg2Index).getWord();
						arg2Index++;
					}
	
					//preparing first argument (person)
					StringBuilder arg1 = new StringBuilder(tokens.get(i).getWord());
					j = i -1;
					
					while ((j >= 0) && (tokens.get(j).getNamedEntityType() == NamedEntityType.PERSON)) {
						arg1.insert(0, tokens.get(j).getWord() + " ");
						j--;
					}
					relations.add(new Relation(RelationName.Live_In,arg1.toString(),arg2,sentenceID));
				}
			}
			return relations;
		}
	}

	//looking for "X...from Y" where X is a person and Y is a location
	public static class LiveInRulePersonFromLoc implements Rule<SentenceWithDependenciesAndNER>{
		@SuppressWarnings("unchecked")
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
			
			//searching the tokens
			for (int i = 0; i < tokens.size() - 1; i++) {
				//found a person
				if ((tokens.get(i).getNamedEntityType() == NamedEntityType.PERSON) && (tokens.get(i + 1).getNamedEntityType() != NamedEntityType.PERSON)) {
					int j = i + 1;
					
					//looking for "from Y" where Y is a location
					while ((j < tokens.size()-1) && !(tokens.get(j+1).getNamedEntityType() == NamedEntityType.LOCATION && (tokens.get(j).getWord().intern()=="from")))
						j++;
					//didn't find or found too far away
					if (j >= tokens.size()-1 || j-i>4)
						continue;
					
					if(j+3<tokens.size() && tokens.get(j+3).getNamedEntityType()==NamedEntityType.PERSON)
						continue;
					int arg2Index=j+1;
					
					//preparing second argument (location)
					String arg2=tokens.get(arg2Index).getWord();
					arg2Index++;
					while(arg2Index<tokens.size() && tokens.get(arg2Index).getNamedEntityType()==NamedEntityType.LOCATION){
						arg2+=" "+tokens.get(arg2Index).getWord();
						arg2Index++;
					}
					
					if(arg2Index+1<tokens.size() && tokens.get(arg2Index+1).getNamedEntityType()==NamedEntityType.PERSON)
						continue;
					
					//preparing first argument (person)
					StringBuilder arg1 = new StringBuilder(tokens.get(i).getWord());
					j = i -1;
					
					while ((j >= 0) && (tokens.get(j).getNamedEntityType() == NamedEntityType.PERSON)) {
						arg1.insert(0, tokens.get(j).getWord() + " ");
						j--;
					}
					relations.add(new Relation(RelationName.Live_In,arg1.toString(),arg2,sentenceID));
				}
			}
			return relations;
		}
	}

	//in sentences related to leaders and politics, looking for a person's name and a location afterwards
	public static class LiveInRuleLeadersLocation implements Rule<SentenceWithDependenciesAndNER>{
		public List<Relation> applyRule(SentenceWithDependenciesAndNER sentence) {
			LinkedList<Relation> relations = new LinkedList<Relation>();
			@SuppressWarnings("unchecked")
			List<TokenWithNER> tokens = (List<TokenWithNER>) sentence.getTokens();
			String sentenceID = tokens.get(0).getSentenceId();
	
			//checking if this sentence is related to a leader
			if(!isRelatedToLeader(sentence))
				return relations;
			
			//searching the tokens
			for(int i=1;i<tokens.size()-2;i++){
				
				//found a person
				if(tokens.get(i).getNamedEntityType()==NamedEntityType.PERSON && tokens.get(i+1).getNamedEntityType()!=NamedEntityType.PERSON){
					
					//preparing first argument (full name of the person)
					String arg1=tokens.get(i).getWord();
					int j=i-1;
					while(j>=0 && tokens.get(j).getNamedEntityType()==NamedEntityType.PERSON){
						arg1=tokens.get(j).getWord()+" "+arg1;
						j--;
					}
	
					//looking for a location
					while(j<tokens.size() && tokens.get(j).getNamedEntityType()!=NamedEntityType.LOCATION)
						j++;
	
					//location not found
					if(j==tokens.size())
						continue;
	
					//preparing second argument
					String arg2=tokens.get(j).getWord();
					j++;
					while(j<tokens.size() && tokens.get(j).getNamedEntityType()==NamedEntityType.LOCATION){
						arg2+=" "+tokens.get(j).getWord();
						j++;
					}
					relations.add(new Relation(RelationName.Live_In,arg1,arg2,sentenceID));
				}
	
			}
			
			
			return relations;
		}
	}

	//this method checks if the sentence is related to leadership/politics
	private static boolean isRelatedToLeader(Sentence sentence){
		
		List<String> relatedWords=new ArrayList<String>();
		relatedWords.add("political");
		relatedWords.add("conference");
		relatedWords.add("government");
		relatedWords.add("president");
		
		//looking for a word with relation to leadership
		List<? extends Token> tokens=sentence.getTokens();
		for(Token token: tokens){
			if(relatedWords.contains(token.getLemma()))
				return true;
		}
		return false;
	}
}
